Technical Q&A QA1287
How can I tell if a PCI device has on board I/O space?


Q:PCI デバイスにオンボード I/O 空間があるかどうか判断するには、どうすればよいのでしょうか。

A:PCI デバイスに I/O 空間、さらにいえばメモリ空間があるかどうかを判断する 1 つの方法は、reg プロパティがどういうもので、Open Firmware が PCI デバイスのreg プロパティをどのように構成しているかを理解することです。以下に簡潔な説明を示します。

reg プロパティは、PCI Bus Supplement to Open Firmware によって定義されています。これは必須のプロパティで、PCI デバイスのオンボードメモリ要件を指定します。実体は、互いに独立したメモリ空間の配列です。PCI デバイスは、3 種類のメモリ空間を持てます。コンフィギュレーション空間は、必ずサポートする必要があります。全部ではありませんが、大半のデバイスはメモリ空間を持ち、中には I/O 空間を持つものもあります。I/O 空間はインテル製プロセッサをサポートしているため、一部の古いタイプの PCI デバイスに見られます。以下に reg プロパティの形式を示す、PCI Bus Supplement の一部を掲載します。このプロパティの実体は、メンバで構成される配列であることを覚えておいてください。後で reg プロパティをデコードする際に、このことが分かるでしょう。

2.2.1.1. 数値表記

アドレスの数値表記は、Open Firmware がアドレスをパッケージメソッドの引数としてプロパティ値やスタックに格納するために使用する形式です。PCI アドレスの数値表記は、3 つのセルで構成され、以下のようにエンコードされています。セルの最下位の 32 ビットがこの目的のために使用され、セルサイズが 32 ビットより大きい場合は、余分な高位のビットはゼロになります。Bit# 0 は最下位ビットを参照します。

         Bit#  33222222 22221111 11111100 00000000
               10987654 32109876 54321098 76543210
phys.hi セル:  npt000ss bbbbbbbb dddddfff rrrrrrrr
phys.mid セル: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
phys.lo セル:  llllllll llllllll llllllll llllllll
ただし:
アドレスが再配置可能な場合、n は 0。再配置不能なら 1。
アドレス指定可能な領域が「プリフェッチ可能」であれば p は 1。可能でなければ 0。
アドレスがエイリアスされている(再配置不能 I/O の場合)、
1 MB 未満(メモリの場合)、
64 KB 未満(再配置可能 I/O の場合)、t は 1。
ss は空間コードで、アドレス空間の種類を示します。
bbbbbbbb は、8 ビットのバス番号。
ddddd は、5 ビットのデバイス番号。
fff は、3 ビットの機能番号。
rrrrrrrr は、8 ビットのレジスタ番号。
hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh は、32 ビットの符号なし数値。
llllllll llllllll llllllll llllllll は、32 ビットの符号なし数値。
これで、PCI アドレスの数値表記が 3 つのセルで構成され、ss フィールドがアドレス空間コードであることが分かります。その形式を以下に示します。

タイプコード "ss" のエンコーディング:

00 コンフィグレーション空間を示します。

01 I/O 空間を示します。

10 32 ビットのアドレス空間を示します。

11 64 ビットのアドレス空間を示します。

reg プロパティは、3 つのアドレスセルと、アドレスサイズを指定する 2 つの追加セルで構成されます。次に、その形式を示します。

reg = {第 1 メンバ:    phys.hi, phys.mid, phys.lo, size.hi, size.lo
       第 2 メンバ:    phys.hi, phys.mid, phys.lo, size.hi, size.lo
            .
            .
       第 n メンバ:    phys.hi, phys.mid, phys.lo, size.hi, size.lo}
これで、Termimal アプリケーションから ioreg ツールを使用して、IORegistry で reg プロパティを見つけ出す準備ができました。しかし、ioreg ツールは、大量のテキストを出力するので煩雑です。以下に、ioreg の使用例を 2 つ示します。最初の例はレジストリ全体をダンプしますが、2 番目の例はレジストリの 1 つのプレーンだけをダンプします。このプレーンは、reg プロパティを 1 つ含んでいる IODeviceTree プレーンです。どちらの例も、出力の量を示すためにパイプを通して wc ツールに出力を渡しています。

Last login: Wed Sep 10 08:36:53 on ttyp1

Welcome to Darwin!

[flanwa:‾] flansbur% ioreg | wc -l

238

[flanwa:‾] flansbur% ioreg -p IODeviceTree | wc -l

73

以下に、後者の例からの出力を示しますが、分かりやすいように一部を省略しています。

+-o Root  <class IORegistryEntry>
  +-o device-tree  <class IOPlatformExpertDevice>
    +-o chosen  <class IOService>
    | +-o memory-map  <class IOService>
    +-o memory@0  <class IOService>
    +-o openprom  <class IOService>
    | +-o client-services  <class IOService>

    |   | +-o ata-3@20000  <class AppleMacIODevice>
    |   | +-o ata-3@21000  <class AppleMacIODevice>
    |   +-o AAPL,NCR8250S@3  <class IOPCIDevice>
AAPL,NCR8250S PCI デバイスに注目することにしましょう。具体的に言うと、このデバイスのプロパティを確認する必要があるとしましょう。この場合も、2 つの方法があります。最初の方法は、ioreg に対してプロバイダに基づいてプロパティをダンプするように命じることです。もう 1 つの方法は、デバイス名に基づいてプロパティをダンプするように命じることです。

[flanwa:‾] flansbur% ioreg -p IODeviceTree -n AAPL,NCR8250S -w 0 | wc -l

101

[flanwa:‾] flansbur% ioreg -p IODeviceTree -c IOPCIDevice -w 0 | wc -l

385

出力量を少なくするために、デバイス名に基づいたダンプを選択することにします。しかしまず、PCI名に関して触れておく必要があります。上記のダンプ(ioreg -p IODeviceTree)では名前が AAPL,NCR8250S@3 ですが、パイプを通して wc に渡した上記の例では名前が AAPL,NCR8250S で、@3 が付いていないことに注目してください。@3 は PCI デバイス AAPL,NCR8250S のユニットアドレスです。複数の PCI デバイスがまったく同じデバイスである場合に対処するために、デバイス名にユニットアドレスを付加する必要があります。たとえば、2 つのネットワークデバイスがあるような場合です。前者のダンプを以下に示します。

[flanwa:‾] flansbur% ioreg -p IODeviceTree -n AAPL,NCR8250S -w 0

+-o Root  <class IORegistryEntry>
  +-o device-tree  <:class IOPlatformExpertDevice>:
    +-o chosen  <:class IOService>:
    | +-o memory-map  <:class IOService>:
    +-o memory@0  <:class IOService>:
.
.
.

    |   +-o AAPL,NCR8250S@3  <:class IOPCIDevice>:
    |   |   {
    |   |     "fcode-rom-offset" = <:00000000>:
    |   |     "IOChildIndex" = 1
    |   |     "model" = <:"8250S">:
    |   |     "reg" = <:000118000000000000000000000
00000000000000201183000000000
00000000000000000000800002011814
00000000000000000000000000000100>:
    |   |     "devsel-speed" = <:00000001>:
ご覧のように、AAPL,NCR8250S の reg プロパティが得られましたが、その出力は配列ではなく、非常に長いテキスト行です。読みやすくするために、テキスト行を 3 行に分割しています。このテキストは、そのままで使えないので、次のステップは、この長いテキスト行を reg プロパティの形式に沿って配列に変換します。形式を再設定した reg プロパティを以下に示します。基数は 16 です。

まず、上記のオリジナル行から開始します。

"reg" = <:000118000000000000000000000

00000000000000201183000000000

00000000000000000000800002011814

00000000000000000000000000000100>:

次に、数値以外のテキストをすべて削除します。

000118000000000000000000000

00000000000000201183000000000

00000000000000000000800002011814

00000000000000000000000000000100

今度は、テキストを以下のように 32 ビット数に区切ります。

00011800|00000000|00000000|

00000000|00000000|02011830|00000000|

00000000|00000000|00008000|02011814|

00000000|00000000|00000000|00000100|

最後に、エントリごとに 5 つの 32 ビット値を持った配列を作成します。各配列メンバには、メモリ記述とサイズが格納されています。この配列を以下に示します。

phy.hi   phy.mid  phy.lo      size.hi  size.lo
00011800 00000000 00000000    00000000 00000000
02011830 00000000 00000000    00000000 00008000
02011814 00000000 00000000    00000000 00000100
以上から、phy.hi の 3 つの 16 進数値は以下のとおりです。

00011800

02011830

02011814

ss 空間コードも基数 16 で、以下のとおりです。

00

02

02

00 はコンフィギュレーション空間で、ほかの 2 つの値(02)は 32 ビットのメモリ空間です。このデバイスは、ボード上に I/O 空間を持っていません。I/O 空間があれば、02011830 が 01011830 であるか、02011814 が 01011814 であるか、あるいはその両方であるはずです。つまり、排他的論理和ではなく、論理和です。



[2003 年 9 月 24 日]